home *** CD-ROM | disk | FTP | other *** search
- /
- / SCC interrupt handler for Atari ST
- /
- / exported functions and variables
- /
- .globl sccvec_,sccnovec_
- .globl scctvec_,sccotvec_,scctim_
- /
- / variables from C
- /
- .globl sccvecloc_,sccmaxvec_,sccpolltab_,sccchan_
- .globl sccisrloc_,sccisrbit_,sccgpiploc_,sccgpipbit_
- /
- .shri
- /
- / sccvec is the interrupt handler for SCC interrupts using INTACK
- /
- sccvec_:
- movem.l ${d0-d2,a0-a2},-(sp) / Save C working registers
- /
- / Determine if an interrupt request is really coming in from SCC
- /
- movea.l sccgpiploc_,a0 / Location of GPIP register
- move.w sccgpipbit_,d0 / Bit number to test
- btst d0,(a0) / Test bit in GPIP data register
- bne.s clrisr / No interrupt, clear ISR & iret
- /
- / Read SCC interrupt vector and check it
- /
- sccint: movea.l sccvecloc_,a0
- move.b $0xff,(a0) / Generate INTACK
- bra delay / Short delay
- delay:
- move.b (a0),d0 / Read the vector
- cmp.b sccmaxvec_,d0 / Check for a legal vector
- bhs.s panic / It should not be >= the maximum
- /
- / Extract channel number and status from vector. Determine handler address.
- /
- move.b d0,d1 / Save vector to retrieve status
- lsr.b $1,d0 / Discard least significant bit
- bcs.s panic / It should not be a 1
- andi.w $0x7c,d0 / Isolate channel number (and make word)
- eori.w $0x04,d0 / Toggle A/B channel bit
- lea sccchan_,a0 / Address SCC channel table
- movea.l 0(a0,d0),a0 / Read address of channel structure
- move.l a0,d0 / Make sure this is an attached channel
- beq.s panic / No channel struct, problems...
- andi.w $0x06,d1 / Isolate status info from vector
- lsl.w $1,d1 / Make index in LONG array
- movea.l 0(a0,d1),a1 / Read the interrupt handler address
- /
- / Call the handler (defined in C), with sccchan struct as a parameter
- /
- move.l a0,-(sp) / Put channel struct as a parameter
- jsr (a1) / Call the handler
- movea.l (sp)+,a0 / Get channel struct back
- / Assumes C routine does not change it
- /
- / Reset highest priority interrupt
- /
- movea.l 16(a0),a1 / Get control register address
- move.b $0x38,(a1) / "Reset Highest IUS" opcode to WR0
- /
- / Clear the ISR bit in the MFP
- /
- clrisr: movea.l sccisrloc_,a0 / Location of ISR
- move.w sccisrbit_,d0 / Bit number to clear
- bclr d0,(a0) / Clear the bit
- /
- / Determine if more interrupt requests are coming in from the SCCs
- /
- movea.l sccgpiploc_,a0 / Location of GPIP register
- move.w sccgpipbit_,d0 / Bit number to test
- btst d0,(a0) / Test bit in GPIP data register
- beq.s sccint / Is active, handle next SCC interrupt
- /
- / Restore registers and return from interrupt handler
- /
- iret: movem.l (sp)+,${d0-d2,a0-a2} / Restore registers
- rte
- /
- / Branch to here when irrecoverable errors occur in the interrupt handler
- /
- panic: illegal / This will cause a TRAP
- movea.l sccisrloc_,a0 / On continuation, clear it and return
- move.w sccisrbit_,d0 / Bit number to clear
- bclr d0,(a0) / Clear the bit
- bra iret
- /
- /
- / sccnovec is the interrupt handler for SCC interrupts using polling
- /
- sccnovec_:
- movem.l ${d0-d2,a0-a2},-(sp) / Save C working registers
- /
- / Determine if an interrupt request is really coming in from SCC
- /
- movea.l sccgpiploc_,a0 / Location of GPIP register
- move.w sccgpipbit_,d0 / Bit number to test
- btst d0,(a0) / Test bit in GPIP data register
- bne.s clrisrnv / No interrupt, clear ISR & iret
- /
- / Find the SCC generating the interrupt by polling all attached SCCs
- / reading RR3A (the interrupt pending register)
- /
- sccintnv:
- movea.l $sccpolltab_,a0 / Point to polling table
- sccpoll:
- move.l (a0)+,d0 / Get chan A CTRL address
- beq.s panic / End of table, we did not find it!
- movea.l d0,a1 / Move it to an address register
- movea.l (a0)+,a2 / Also read B CTRL address
- move.b $3,(a1) / Select RR3A
- move.b (a1),d0 / Read it and test for 0
- beq.s sccpoll / No interrupt here, try next chip
- /
- / Read SCC interrupt vector from RR2B, it should always be correct
- / Extract channel number and status from vector. Determine handler address.
- /
- move.b $2,(a2) / Select RR2B
- move.b (a2),d0 / Read the vector
- move.b d0,d1 / Save vector to retrieve status
- lsr.b $1,d0 / Discard least significant bit
- andi.w $0x7c,d0 / Isolate channel number (and make word)
- eori.w $0x04,d0 / Toggle A/B channel bit
- lea sccchan_,a0 / Address SCC channel table
- movea.l 0(a0,d0),a0 / Read address of channel structure
- move.l a0,d0 / Make sure this is an attached channel
- beq.s panic / No channel struct, problems...
- andi.w $0x06,d1 / Isolate status info from vector
- lsl.w $1,d1 / Make index in LONG array
- movea.l 0(a0,d1),a1 / Read the interrupt handler address
- /
- / Call the handler (defined in C), with sccchan struct as a parameter
- /
- move.l a0,-(sp) / Put channel struct as a parameter
- jsr (a1) / Call the handler
- addq.l $4,sp / Remove parameter
- /
- / Clear the ISR bit in the MFP
- /
- clrisrnv:
- movea.l sccisrloc_,a0 / Location of ISR
- move.w sccisrbit_,d0 / Bit number to clear
- bclr d0,(a0) / Clear the bit
- /
- / Determine if more interrupt requests are coming in from the SCCs
- /
- movea.l sccgpiploc_,a0 / Location of GPIP register
- move.w sccgpipbit_,d0 / Bit number to test
- btst d0,(a0) / Test bit in GPIP data register
- beq.s sccintnv / Is active, handle next SCC interrupt
- /
- / Restore registers and return from interrupt handler
- /
- movem.l (sp)+,${d0-d2,a0-a2} / Restore registers
- rte
- /
- /
- / This routine will be inserted in the 200Hz timer interrupt handling
- / (vector 0x114) to call the SCC driver timing routine every 2nd
- / interrupt (= every 10 ms), and thereafter jump to the original handler
- /
- scctvec_:
- btst $0,0x4bd / Test low bit of 200Hz counter
- beq.s punt / Not our turn
- movem.l ${d0-d2,a0-a2},-(sp) / Save C working registers
- jsr scctim_ / Call C routine every 10 ms
- movem.l (sp)+,${d0-d2,a0-a2} / Restore registers
- punt: jmp 0xeeeeeeee / Jump to original handler
- sccotvec_ = .-4 / Original hander address stored here
-
-